<html>
    <head>
        <title>额外属性</title>
    </head>
    <body>
        <script>
  /*
                        六、额外属性

                                ABP定义了IHasExtraProperties接口，该接口可以由实体实现，以便能够动态设置和获取实体的属性。

                                AggregateRoot基类已经实现了IHasExtraProperties接口。

                                如果你是从这个类派生的（或者上面定义的相关审计类之一），你可以直接使用API。


                               

                                1、GetProperty 和  SetProperty 扩展方法

                                            这些扩展方法时获取和设置实体数据的推荐方法。

                                            eg：

                                                // 声明一个额外属性服务
                                                public class ExtraPropertiesDemoService : ITransientDependency
                                                {
                                                    private readonly IIdentityUserRepository _identityUserRepository;

                                                    public ExtraPropertiesDemoService(IIdentityUserRepository identityUserRepository)
                                                    {
                                                        _identityUserRepository = identityUserRepository;
                                                    }

                                                    public async Task SetTitle(Guid userId, string title)
                                                    {
                                                        var user = await _identityUserRepository.GetAsync(userId);
                                                        
                                                        // 设置属性值
                                                        user.SetProperty("Title", title);
                                                        
                                                        await _identityUserRepository.UpdateAsync(user);
                                                    }

                                                    public async Task<string> GetTitle(Guid userId)
                                                    {
                                                        var user = await _identityUserRepository.GetAsync(userId);

                                                        // 获取属性值
                                                        return user.GetProperty<string>("Title");
                                                    }
                                                }

                                            属性的值是object，可以是任何类型的对象（字符串、int、bool…等）。

                                            GetProperty如果之前未设置给定属性，则返回null。

                                            你可以使用不同的属性名称同时存储多个属性（如此处的Title）


                                            为属性名称定义一个常量以防止错别字错误将是一种很好的做法。

                                            定义扩展方法以利用智能感知甚至是一种更好的做法。
                                            
                                            例子：

                                                // 扩展IdentityUser 类
                                                public static class IdentityUserExtensions
                                                {
                                                    // 定义常量作为属性名，防止写错
                                                    private const string TitlePropertyName = "Title";

                                                    // 定义属性设置方法
                                                    public static void SetTitle(this IdentityUser user, string title)
                                                    {
                                                        user.SetProperty(TitlePropertyName, title);
                                                    }

                                                    // 定义获取属性的方法
                                                    public static string GetTitle(this IdentityUser user)
                                                    {
                                                        return user.GetProperty<string>(TitlePropertyName);
                                                    }
                                                }

                                            后你可以直接将user.SetTitle("...")和user.GetTitle()用于IdentityUser对象。


                                2、HasProperty和RemoveProperty扩展方法
                                
                                            HasProperty用于检查对象之前是否设置了属性。

                                            RemoveProperty用于从对象中删除属性。你可以使用它而不是设置null值
                                        
                                             Create


                                3、额外属性是如何实现的？

                                            IHasExtraProperties接口需要为实现的类定义一个名为ExtraProperties的Dictionary<string, object>属性。

                                            因此，如果你愿意，你可以直接使用ExtraProperties属性来使用字典API。

                                            但是，SetProperty和GetProperty方法是推荐的方法，因为它们还检查nulls。


                                            ①、额外属性是如何存储的？

                                                    将此字典存储在数据库中的方式取决于你使用的数据库提供程序。

                                                    对于Entity Framework Core，这里有两种类型的配置：

                                                        （1）、默认情况下，它作为JSON字符串存储在单个ExtraProperties字段中
                                                               
                                                               （这意味着所有额外的属性都存储在单个数据库表字段中）。


                                                        （2）、如果需要，可以使用ObjectExtensionManager为所需的额外属性定义单独的表字段。

                                                               未通过ObjectExtensionManager配置的属性将继续使用如上所述的单个JSON字段。

                                                               当你正在使用预构建的应用程序模块并希望扩展其实体时，此功能特别有用。

                                                               请参阅EF Core集成文档以了解如何使用ObjectExtensionManager。

                                                    对于MongoDB，它被存储为常规字段，因为MongoDB自然支持这种额外元素系统。


                                 4、关于额外属性的讨论

                                        如果你使用定义内部实体的可重用模块并且你希望以简单的方式获取/设置与该实体相关的一些数据，
                                        
                                        则Extra Properties系统特别有用。

                                        你通常不需要将此系统用于你自己的实体，因为它具有以下缺点：

                                                它是不是完全类型安全的，因为它使用字符串作为属性名称。

                                                自动将这些属性从/映射到其他对象并不容易。


                                        除了实体，其他任何类只要实现了 IHasExtraProperties，你就可以为任何类搞额外属性的扩展。
                    */
        </script>
    </body>
</html>